#include <cstdlib>
#include <cmath>
#include <SDL.h>

const int WinWidth = 640;
const int WinHeight = 480;

SDL_Surface *screen;

void InitSDL()
{
	if (SDL_Init(SDL_INIT_VIDEO) != 0) {
		exit(EXIT_FAILURE);
	}
	atexit(SDL_Quit);
}

void InitEvents()
{
	SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
}

void OpenWindow(const int width, const int height)
{
	if ((screen = SDL_SetVideoMode(width, height, 32, SDL_SWSURFACE)) == NULL) {
		exit(EXIT_FAILURE);
	}
}

void PutPixel(const int x, const int y, const Uint8 r, const Uint8 g, const Uint8 b)
{
	Uint32 pixval = SDL_MapRGB(screen->format, r, g, b);

	((Uint32 *)screen->pixels)[y * (screen->pitch / screen->format->BytesPerPixel) + x] = pixval;
}

#pragma warning (once: 4244)
void DrawAntialiasedLine(int x1, int y1, int x2, int y2, const Uint8 r, const Uint8 g, const Uint8 b)
{
	const int dx = x2 - x1;
	const int dy = y2 - y1;
	double steps = (abs(dx) > abs(dy)) ? abs(dx) : abs(dy);
	double x, y, fract;

	for (int i = 0; i < steps; ++i) {
		x = x1 + dx * i / steps;
		y = y1 + dy * i / steps;
		if (abs(dx) > abs(dy)) {
			fract = 1 - (y - floor(y));
			PutPixel(floor(x + 0.5), floor(y), r * fract, g * fract, b * fract);
			fract = 1 - (ceil(y) - y);
			PutPixel(floor(x + 0.5), ceil(y), r * fract, g * fract, b * fract);
		} else {
			fract = 1 - (x - floor(x));
			PutPixel(floor(x), floor(y + 0.5), r * fract, g * fract, b * fract);
			fract = 1 - (ceil(x) - x);
			PutPixel(ceil(x), floor(y + 0.5), r * fract, g * fract, b * fract);
		}
	}
}
#pragma warning (default: 4244)

void DrawBresenhamLine(int x1, int y1, int x2, int y2, const Uint8 r, const Uint8 g, const Uint8 b)
{
	int dx = x2 - x1;
	int dy = y2 - y1;
	const int incrx = dx / abs(dx);
	const int incry = dy / abs(dy);

	int absdx, absdy;
	if (abs(dx) > abs(dy)) {
		absdx = abs(dx);
		absdy = abs(dy);
	} else {
		absdx = abs(dy);
		absdy = abs(dx);
	}

	const int dy2 = absdy * 2;
	const int dydx2 = dy2 - 2 * absdx;
	int p = dy2 - absdx;

	for (int i = 0; i <= absdx; ++i) {
		PutPixel(x1, y1, r, g, b);

		if (abs(dx) > abs(dy)) {
			x1 += incrx;
			if (p >= 0) {
				y1 += incry;
				p += dydx2;
			} else {
				p += dy2;
			}
		} else {
			y1 += incry;
			if (p >= 0) {
				x1 += incrx;
				p += dydx2;
			} else {
				p += dy2;
			}
		}
	}
}

#pragma warning (disable: 4100)
void DrawFrame(SDL_Event *ev, SDL_Event *oldev)
{
	if (SDL_MUSTLOCK(screen)) {   
		SDL_LockSurface(screen);
	}

	//DrawAntialiasedLine(oldev->motion.x, oldev->motion.y, ev->motion.x, ev->motion.y, 255, 255, 0);
	DrawBresenhamLine(100, 100, ev->button.x, ev->button.y, 255, 255, 0);

	SDL_UnlockSurface(screen);

	SDL_Flip(screen);
}
#pragma warning (default: 4100)

#pragma warning (disable: 4100)
int main(int argc, char *argv[])
{
	SDL_Event ev, oldev;
	//bool draw = false;

	memset(&oldev, 0, sizeof(oldev));

	InitSDL();
	OpenWindow(WinWidth, WinHeight);
	InitEvents();

	do {
		SDL_WaitEvent(&ev);

		if (ev.type == SDL_MOUSEBUTTONDOWN) {
			DrawFrame(&ev, NULL);
		}
		/*
		switch (ev.type) {
			case SDL_MOUSEBUTTONDOWN:
				draw = true;
				break;
			case SDL_MOUSEBUTTONUP:
				draw = false;
				break;				
			case SDL_MOUSEMOTION:
				if (draw && (oldev.type == SDL_MOUSEMOTION)) {
					DrawFrame(&ev, &oldev);
				}
				oldev = ev;
		}
		*/
	} while (ev.type != SDL_KEYDOWN);

	return EXIT_SUCCESS;
}
#pragma warning (default: 4100)
